#include "widget.h"
#include "ui_widget.h"
#include "dialog.h"
#include "index.h"
#include "ppyldialog.h"
#include <QPainter>
#include <QGraphicsDropShadowEffect>
#include <QTime>
#include <QMessageBox>
#include <QDesktopWidget>
#include <QDebug>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    setWindowTitle(tr("算法验证")) ;
    setMinimumSize(800,600);
    setMaximumSize(800,600);
    //设置具体阴影
    QGraphicsDropShadowEffect *shadow_effect = new QGraphicsDropShadowEffect(this);
    shadow_effect->setOffset(0, 0);
    //阴影颜色
    shadow_effect->setColor(QColor(38, 78, 119, 127));
    //阴影半径
    shadow_effect->setBlurRadius(22);
    ui->start->setGraphicsEffect(shadow_effect);
    //按钮设置
    ui->comboBox->move(620, 100);ui->yzylBtn->move(580, 480);ui->exitBtn->move(690,480);//设置按钮位置
    ui->psBtn->move(580,430);ui->ppylBtn->move(690,430);ui->pauseBtn->move(580,380);
    ui->start->move(635,280);
}
// 延时器，等待 msec 秒，用于动画中的等待时间
bool Delay_MSec_Suspend(unsigned int msec)      // 程序等待 msec 毫秒
{
    QTime time;
    time.start();
    while(time.elapsed() < msec)//等待时间流逝 msec 毫秒
    QCoreApplication::processEvents();//处理事件
    return true ;
}
// 找到下一个没被铺设的点的坐标，如果没有了返回 -1 ， -1
pair<int , int> Widget::find_next(int x , int y) {
    int i = x , j = y + 1 ;     
    for ( ; j <= n ; ++ j) {
        if (w[i][j] == false)// 没被铺设
            return {i , j} ;
    }
    for (i += 1 ; i <= n ; ++ i) {
        for (j = 1 ; j <= n ; ++ j) {
            if (w[i][j] == false)// 没被铺设
                return {i , j} ;
        }
    }
    return {-1 , -1} ;
}
// dfs
bool Widget::dfs(int x , int y) {
    if (tot == n * n) {         // 说明铺设完了
        Delay_MSec_Suspend(1000) ;
        update() ;      // 更新画图
        return tot != 0 ;
    }
    for (int i = 0 ; i < 4 ; ++ i) {        // 查找四个方向
        vector<pair<int , int>> q ;     // 存储这张骨牌的所有点的坐标
        bool out = false , covered = false ;
        for (auto &j : card[status][i]) {       // 遍历这个骨牌的第 i 个方向的所有点的相对坐标
            if (x + j[0] >= 1 && x + j[0] <= n && y + j[1] >= 1 && y + j[1] <= n){
                if (w[x + j[0]][y + j[1]] == true)
                    covered = true ;        // 说明当前这张牌放下会跟之前的牌重叠
                q.push_back({x + j[0] , y + j[1]}) ;        // 存下这个点的坐标
            }
            else {
                out = true ;    // 说明当前这张牌有地方出了棋盘了
            }
        }
        if (out)        // 如果出棋盘了，不管，查找下一个
            continue ;
        cards.push_back(q) ;
        if (covered) {      // 如果重叠了，最后一张牌为红色，画一下
            enable = false ;
            Delay_MSec_Suspend(1000) ;
            update() ;
            enable = true ;
            cards.pop_back() ;      // 删除这张牌，继续下一次查找
            Delay_MSec_Suspend(1000) ;  
            update() ;
        }
        else {      // 如果这张牌可以铺下
            for (auto &i : q) {         // 将这张牌铺下
                w[i.first][i.second] = true ;
            }
            Delay_MSec_Suspend(1000) ;
            update() ;      // 更新绘图
            pair<int , int> ne = {x , y} ;          // 查找下一个没有被铺设的点
            while (ne.first != -1 && ne.second != -1) {
                ne = find_next(ne.first , ne.second) ;
                tot += 4 ;      // 铺设
                bool ans = dfs(ne.first , ne.second) ;      // 深搜
                if (ans)        // 如果铺设完了，返回true
                    return true ;
                tot -= 4 ;
            }
            for (auto &i : q) {         // 深搜完了， 回溯，清楚当前这张牌，查看下一种情况
                w[i.first][i.second] = false ;
            }
            cards.pop_back() ;
        }
    }
    return false ;
}
// QT 画笔必须在这个函数里面使用
void Widget::paintEvent(QPaintEvent *p){
    QPainter painter(this) ;
    //画背景图
    if(!chessboard){
        painter.drawPixmap(38,23,524,525, QPixmap(":/images/bg.jpg"));
        return;
    }
    painter.drawPixmap(38,23,524,525, QPixmap(":/img/images/qipan.jpg"));
    painter.setPen(QPen(Qt::black)) ;       // 设置画笔的颜色为黑色，宽度默认为1
    for (int i = 0 ; i <= 8 ; ++ i) {       // 画棋盘的格子线
        painter.drawLine(startx , starty + i * size , startx + 8 * size , starty + i * size) ;
        painter.drawLine(startx + i * size , starty , startx + i * size , starty + 8 * size) ;
    }
    if (n == 0)
        return ;
    unsigned int m = (unsigned int)cards.size() ;       // 获取有多少张牌

    //唯一的算法
    for (unsigned int i = 0 ; i < m ; ++ i) {
        if (enable || i != m - 1){          // 如果不是最后一张牌或者最后一张牌没有重叠现象，设置颜色
            painter.setPen(QPen(QColor(color[i][0] , color[i][1] , color[i][2]) , size - 1)) ;
        }
        else {      // 如果最后一张牌是重叠的，最后一张牌设置为红色
            painter.setPen(QPen(Qt::red , size - 2)) ;
        }
        for (auto &j : cards[i]) {
            painter.drawPoint(startx + (j.first - 1) * size + size / 2 , starty + (j.second - 1) * size + size / 2) ;
        }
    }
}

void Widget::on_comboBox_activated(int index)
{
    n = 0 ;
    status = index ;        // 获取用户选择的是哪种骨牌
    update() ;
}
// 开始干活
void Widget::on_start_clicked()
{
    if(!chessboard){
        QMessageBox::information(this , tr("提示") , tr("请先铺设棋盘")) ;
        return ;
    }
    memset(w , false , sizeof w) ;
    Delay_MSec_Suspend(1000) ;
    cards.clear() ;
    update() ;
    QPainter painter(this) ;
    for (int i = 0 ; i <= 8 ; ++ i) {       // 画棋盘的格子线
        painter.drawLine(startx , starty + i * size , startx + 8 * size , starty + i * size) ;
        painter.drawLine(startx + i * size , starty , startx + i * size , starty + 8 * size) ;
    }
    tot = 0 ;
    n = 4 ;
    bool ans = dfs(1 , 1) ;//找出前1/4的解，如果返回的是true，说明找到了
    // 根据dfs找出的解答，将其余的3/4给画出来。
    if (ans) {
        int m = cards.size() ;
        for (int i = 0 ; i < m ; ++ i) {
            vector<pair<int , int>> q ;
            for (auto &j : cards[i]) {
                q.push_back({j.first , j.second + 4}) ;
            }
            cards.push_back(q) ;
            Delay_MSec_Suspend(1000) ;
            update() ;
        }
        m = cards.size() ;
        for (int i = 0 ; i < m ; ++ i) {
            vector<pair<int , int>> q ;
            for (auto &j : cards[i]) {
                q.push_back({j.first + 4 , j.second}) ;
            }
            cards.push_back(q) ;
            Delay_MSec_Suspend(1000) ;
            update() ;
        }
    }
    else {
        if (n != 0){
            n = 8 ;
            bool res = dfs(1 , 1) ;
            if (!res){
                QMessageBox::information(this , tr("提示") , tr("无法铺满")) ;
                return ;
            }
        }
    }
    if (n == 4 || n == 8)
        QMessageBox::information(this , tr("提示") , tr("铺设完成")) ;
}
Widget::~Widget()
{
    delete ui;
}

void Widget::on_exitBtn_clicked()
{
    //退出对话框
    // 创建一个question弹出对话框，添加两个按钮：Yes和No
    if(QMessageBox::Yes==QMessageBox::question(this,"提示","你确定要返回到开始界面？",QMessageBox::Yes|QMessageBox::No))
    {
        cards.clear() ;
        this->hide();
        index *i=new index();
        i->show();
    }
}
void Widget::on_yzylBtn_clicked()
{
    dialog=new Dialog(this);
    dialog->exec();
}
void Widget::on_psBtn_clicked()
{
    chessboard=true;
    update();
}
void Widget::on_ppylBtn_clicked()
{
    pplydialog=new ppylDialog(this);
    pplydialog->exec();
}

void Widget::on_pauseBtn_clicked()
{
    if(isPause==false){
        isPause=true;
        ui->pauseBtn->setText("继续");
    }
    else {
        isPause=false;
        ui->pauseBtn->setText("暂停");
    }
    while(isPause){
         QCoreApplication::processEvents();//处理事件
    }
}

